# -*- coding: utf-8 -*-
# Copyright 2011-2012 MagiCycles.com
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import datetime

from google.appengine.api import users
from google.appengine.api import memcache

from datastore.common import UserNotExistError
from datastore.people import SiteUser,OutSiteUser,Anonymous,Activity


import common
from common import *
from common import Box

def _Rider_Encoder(rider):
    from common import _S,unescape
    if isinstance(rider, SiteUser):
        return {"name": unescape(rider.name),
                "photourl": unescape(rider.photourl),
                "uid": rider.uid,
                "join_datetime": rider.join_datetime,
                "last_login_datetime": rider.last_login_datetime,
                "intro": unescape(rider.intro),
                "location": _S(rider.location),
                "city": unescape(rider.city),
                "state": unescape(rider.state),
                "country": unescape(rider.country),
                "point": rider.Point,
                "suns": len(rider.Suns),
                "stars": len(rider.Stars),
                "routes_count": rider.Stats.routes_count,
                "routes_total_distance": rider.Stats.routes_total_distance,
                "rides_count": rider.Stats.rides_count,
                "rides_total_distance": rider.Stats.rides_total_distance,
                "hours_on_bike": rider.Stats.hours_on_bike,
                }
    elif isinstance(rider, datetime.datetime):
        return rider.isoformat()
    else:
        raise TypeError('%r is not JSON serializable' % rider)

get_current_user = common.get_current_user

def new_site_user(outsiteuser, uid, name, **kwds):
    return SiteUser.create_from_outsiteuser(outsiteuser, uid, name, **kwds)

def get_user_by_uid(uid):
    return SiteUser.get_by_uid(uid)

def get_outuser_by_uid(uid):
    return OutSiteUser.get_by_uid(uid)

def is_user_exist(uid):
    return SiteUser.check_user_exist(uid)

def get_anonymous_user():
    return Anonymous

def save_user_profile(uid, profile_dict):
    user = get_user_by_uid(uid)
    if user:
        user.set_settings(**profile_dict)
        user.save()
    else:
        raise UserNotExistError("user %s is not existed."%uid)

def save_outuser_profile(uid, profile_dict):
    outuser = get_outuser_by_uid(uid)
    if outuser:
        outuser.set_settings(**profile_dict)
        outuser.save()
    else:
        raise UserNotExistError("outuser %s is not existed."%uid)

def get_activity_by_id(id):
    id = long(id)
    return Activity.get_by_id(id)

@check_site_user
def get_rider_by_uid(request, uid):
    """return rider by uid.
    Args:
      uid: rider login account
    Returns:
      rider: json serialized rider.
    """
    rider = get_user_by_uid(uid)
    if rider:
        result = {"status": "ok",
                  "rider": rider,
                  "custom_encoder": _Rider_Encoder}
    else:
        result = {"status": "error",
                  "message": "can not found rider %s"%uid}

    return result

def get_riders_by_bounds(request, north, east, south, west, max_results=1000):
    """return riders in bounds.
    Args:
      north, east, south, west: bounds of google map
      max_results: max count of items return
    Returns:
      riders: list(rider), list of json serialized rider.
    """
    max_results = long(max_results)
    bounds = Box(float(north),float(east),float(south),float(west))
    cache_key = "get_riders_by_bounds_%s_(N:%.1f, E:%.1f, S:%.1f, W:%.1f)"%(max_results,
                                                                    bounds.north, bounds.east,
                                                                    bounds.south, bounds.west)
    riders = memcache.get(cache_key)
    if riders is None:
        riders = SiteUser.search_by_bounds(bounds, max_results)
        riders = [_Rider_Encoder(rider) for rider in riders if rider is not None]
        memcache.set(cache_key, riders)

    result = {"status": "ok",
              "riders": riders,
              "custom_encoder": _Rider_Encoder}
    return result

def get_riders_count_by_bounds(request, north, east, south, west):
    """return number of riders in bounds.
    Args:
      north, east, south, west: bounds of google map
    Returns:
      count: int, number of riders in bounds.
    """
    bounds = Box(float(north),float(east),float(south),float(west))
    cache_key = "get_riders_count_by_bounds_(N:%.1f, E:%.1f, S:%.1f, W:%.1f)"%(bounds.north, bounds.east,
                                                                            bounds.south, bounds.west)
    count = memcache.get(cache_key)
    if count is None:
        count = SiteUser.count_by_bounds(bounds)
        memcache.set(cache_key, count)

    result = {"status": "ok",
              "count": count,
              }
    return result

@check_site_user
def send_friend_request(request, friend_uid):
    """request a friendship with the rider
    Args:
      friend_uid: friend's login account
    Returns:
      None.
    """
    me = get_current_user()
    friend = get_user_by_uid(friend_uid)
    if me and friend:
        SiteUser.new_friend_request(me.uid, friend.uid)
        result = {"status": "ok"}
    else:
        result = {"status": "error",
                  "message": "can not found rider %s"%friend_mail}

    return result

@check_site_user
def confirm_friend_request(request, friend_uid, agree="yes"):
    """confirm a friendship with the rider
    Args:
      friend_uid: friend's login account
      agree: "yes" or "no"
    Returns:
      None.
    """
    me = get_current_user()
    friend = get_user_by_uid(friend_uid)
    if me and friend:
        SiteUser.confirm_friend_request(me.uid, friend.uid, agree=="yes")
        result = {"status": "ok"}
    else:
        result = {"status": "error",
                  "message": "can not found rider %s"%friend_uid}

    return result

@check_site_user
def defriend(request, friend_uid):
    """remove friendship with the rider
    Args:
      friend_uid: friend's login account
    Returns:
      None.
    """
    me = get_current_user()
    friend = get_user_by_uid(friend_uid)
    if me and friend:
        SiteUser.remove_friendship(me.uid, friend.uid)
        result = {"status": "ok"}
    else:
        result = {"status": "error",
                  "message": "can not found rider %s"%friend_uid}

    return result

@check_site_user
def add_favorite_route(request, routeid):
    """ add a route into user's favorites
    Args:
      routeid: route id
    Returns:
      None.
    """
    from routes_api import _Route_Encoder
    rider = get_current_user()
    route = rider.add_favorite(long(routeid))
    if route:
        return {"status": "ok",
                "route": route,
                "custom_encoder": _Route_Encoder}
    else:
        return {"status": "error",
                "message": "route not found"}

@check_site_user
def remove_favorite_route(request, routeid):
    """ remove a route from user's favorites
    Args:
      routeid: route id
    Returns:
      None.
    """
    from routes_api import _Route_Encoder
    rider = get_current_user()
    route = rider.remove_favorite(long(routeid))
    if route:
        return {"status": "ok",
                "route": route,
                "custom_encoder": _Route_Encoder}
    else:
        return {"status": "error",
                "message": "route not found"}

@check_site_user
def unbind_outsite(request, uid, outuser_uid):
    """ Unbind outsite account
    Args:
      uid: user's login account
      outuser_uid: outuser's uid
    Returns:
      None.
    """
    import outusers
    user = get_current_user()
    if user.uid != uid and not users.is_current_user_admin():
        return {"status": "error",
                "message": "no authorization"}

    outuser = OutSiteUser.get_by_uid(outuser_uid)
    if not outuser:
        return {"status": "error",
                "message": "no outuser %s"%outuser_uid}

    if outuser.uid == outusers.get_outsite_user().uid:
        return {"status": "error",
                "message": "can not unbind current login account"}

    user.unbind_outsite_user(user, outuser)
    outusers.refresh_outsite_user()

    return {"status": "ok"}

def search_riders(request, search_text, pagesize=50, start_cursor=None, order="-last_login_datetime"):
    """full text search for riders.
    Args:
      search_text: search words
      pagesize: size of results
      start_cursor: start cursor positon for this search
      orders: ordering for the results
    Returns:
      end_cursor: cursor position for next search,
      riders: list(route), list of json serialized rider.
    """
    pagesize = long(pagesize)
    riders,end_cursor = SiteUser.search_by_text(search_text, pagesize=pagesize,
        start_cursor=start_cursor, order=order)
    return {"status": "ok",
            "end_cursor": end_cursor,
            "riders": riders,
            "custom_encoder": _Rider_Encoder}

def main():
    pass

if __name__ == '__main__':
    main()
